pub fn compile(manifest_path: &Path,
options: &mut CompileOptions)
- -> CargoResult<HashMap<PackageId, Vec<Path>>> {
+ -> CargoResult<ops::Compilation> {
let CompileOptions { update, env, ref mut shell, jobs, target } = *options;
let target = target.map(|s| s.to_string());
try!(src.update());
let root = try!(src.get_root_package());
- try!(ops::compile(manifest_path, options));
+ let compile = try!(ops::compile(manifest_path, options));
let exe = manifest_path.dir_path().join("target").join(root.get_name());
let exe = match exe.path_relative_from(&os::getcwd()) {
Some(path) => path,
None => exe,
};
- let process = process(exe).args(args);
+ let process = compile.process(exe).args(args);
try!(options.shell.status("Running", process.to_string()));
Ok(process.exec().err())
--- /dev/null
+use std::collections::HashMap;
+use std::dynamic_lib::DynamicLibrary;
+use std::os;
+
+use core::PackageId;
+use util;
+
+/// A structure returning the result of a compilation.
+pub struct Compilation {
+ /// All libraries which were built for a package.
+ ///
+ /// This is currently used for passing --extern flags to rustdoc tests later
+ /// on.
+ pub libraries: HashMap<PackageId, Vec<Path>>,
+
+ /// An array of all tests created during this compilation.
+ pub tests: Vec<Path>,
+
+ /// An array of all binaries created.
+ pub binaries: Vec<Path>,
+
+ /// All directires for the output of native build commands.
+ ///
+ /// This is currently used to drive some entries which are added to the
+ /// LD_LIBRARY_PATH as appropriate.
+ pub native_dirs: HashMap<PackageId, Path>,
+
+ /// Root output directory (for the local package's artifacts)
+ pub root_output: Path,
+
+ /// Output directory for rust dependencies
+ pub deps_output: Path,
+}
+
+impl Compilation {
+ pub fn new() -> Compilation {
+ Compilation {
+ libraries: HashMap::new(),
+ native_dirs: HashMap::new(),
+ root_output: Path::new("/"),
+ deps_output: Path::new("/"),
+ tests: Vec::new(),
+ binaries: Vec::new(),
+ }
+ }
+
+ /// Prepares a new process with an appropriate environment to run against
+ /// the artifacts produced by the build process.
+ pub fn process<T: ToCStr>(&self, cmd: T) -> util::ProcessBuilder {
+ let mut search_path = DynamicLibrary::search_path();
+ for dir in self.native_dirs.values() {
+ search_path.push(dir.clone());
+ }
+ search_path.push(self.root_output.clone());
+ search_path.push(self.deps_output.clone());
+ let search_path = os::join_paths(search_path.as_slice()).unwrap();
+ util::process(cmd).env(DynamicLibrary::envvar(),
+ Some(search_path.as_slice()))
+ }
+}
use util;
use util::{CargoResult, ChainError, internal, Config, profile};
-use super::{Kind, KindPlugin, KindTarget};
+use super::{Kind, KindPlugin, KindTarget, Compilation};
use super::layout::{Layout, LayoutProxy};
#[deriving(Show)]
pub config: &'b mut Config<'b>,
pub resolve: &'a Resolve,
pub sources: &'a SourceMap,
+ pub compilation: Compilation,
env: &'a str,
host: Layout,
target_exe: target_exe,
host_dylib: host_dylib,
requirements: HashMap::new(),
+ compilation: Compilation::new(),
})
}
self.build_requirements(pkg, target, Target, &mut HashSet::new());
}
+ self.compilation.root_output = self.layout(KindTarget).proxy().dest().clone();
+ self.compilation.deps_output = self.layout(KindTarget).proxy().deps().clone();
+
Ok(())
}
};
let is_rustc_fresh = try!(is_fresh(&old_loc, rustc_fingerprint.as_slice()));
- let layout = cx.layout(kind);
+ let (old_root, root) = {
+ let layout = cx.layout(kind);
+ (layout.old_root().clone(), layout.root().clone())
+ };
let mut pairs = vec![(old_loc, new_loc.clone())];
if !target.get_profile().is_doc() {
pairs.push((old_dep_info, new_dep_info));
- pairs.extend(cx.target_filenames(target).iter().map(|filename| {
+
+ for filename in cx.target_filenames(target).iter() {
let filename = filename.as_slice();
- ((layout.old_root().join(filename), layout.root().join(filename)))
- }));
+ let dst = root.join(filename);
+ pairs.push((old_root.join(filename), root.join(filename)));
+
+ if target.get_profile().is_test() {
+ cx.compilation.tests.push(dst.clone());
+ } else if target.is_bin() {
+ cx.compilation.binaries.push(dst.clone());
+ } else if target.is_lib() && target.get_profile().is_compile() {
+ let pkgid = pkg.get_package_id().clone();
+ cx.compilation.libraries.find_or_insert(pkgid, Vec::new())
+ .push(root.join(filename));
+ }
+ }
}
Ok(prepare(is_rustc_fresh && are_files_fresh, new_loc, rustc_fingerprint,
let new_fingerprint = mk_fingerprint(cx, &new_fingerprint);
let is_fresh = try!(is_fresh(&old_loc, new_fingerprint.as_slice()));
- let layout = cx.layout(kind);
let pairs = vec![(old_loc, new_loc.clone()),
- (layout.old_native(pkg), layout.native(pkg))];
+ (cx.layout(kind).old_native(pkg),
+ cx.layout(kind).native(pkg))];
+
+ let native_dir = cx.layout(kind).native(pkg);
+ cx.compilation.native_dirs.insert(pkg.get_package_id().clone(), native_dir);
Ok(prepare(is_fresh, new_loc, new_fingerprint, pairs))
}
-use std::collections::{HashSet, HashMap};
+use std::collections::HashSet;
use std::dynamic_lib::DynamicLibrary;
use std::io::{fs, UserRWX};
use std::os;
use self::job_queue::{StageBinaries, StageEnd};
use self::context::{Context, PlatformRequirement, Target, Plugin, PluginAndTarget};
+pub use self::compilation::Compilation;
+
mod context;
+mod compilation;
mod fingerprint;
mod job;
mod job_queue;
deps: &PackageSet, resolve: &'a Resolve,
sources: &'a SourceMap,
config: &'a mut Config<'a>)
- -> CargoResult<HashMap<PackageId, Vec<Path>>> {
+ -> CargoResult<Compilation> {
if targets.is_empty() {
- return Ok(HashMap::new());
+ return Ok(Compilation::new())
}
debug!("compile_targets; targets={}; pkg={}; deps={}", targets, pkg, deps);
cx.primary();
try!(compile(targets, pkg, &mut cx, &mut queue));
- let ret = build_return_map(&cx, pkg, deps);
-
// Now that we've figured out everything that we're going to do, do it!
try!(queue.execute(cx.config));
- Ok(ret)
+ Ok(cx.compilation)
}
fn compile<'a, 'b>(targets: &[&'a Target], pkg: &'a Package,
Some(ret)
}
-
-fn build_return_map(cx: &Context, root: &Package, deps: &PackageSet)
- -> HashMap<PackageId, Vec<Path>> {
- let mut ret = HashMap::new();
- match cx.resolve.deps(root.get_package_id()) {
- Some(mut my_deps) => {
- for dep in my_deps {
- let pkg = deps.iter().find(|p| p.get_package_id() == dep).unwrap();
- ret.insert(dep.clone(), build_paths(cx, pkg, false));
- }
- }
- None => {}
- }
- ret.insert(root.get_package_id().clone(), build_paths(cx, root, true));
- return ret;
-
- fn build_paths(cx: &Context, pkg: &Package, root: bool) -> Vec<Path> {
- pkg.get_targets().iter().filter(|target| {
- target.get_profile().is_compile() && target.is_lib()
- }).flat_map(|target| {
- let kind = if target.get_profile().is_plugin() {
- KindPlugin
- } else {
- KindTarget
- };
- let layout = cx.layout(kind);
- cx.target_filenames(target).move_iter().map(|filename| {
- let root = if root {layout.root()} else {layout.deps()};
- root.join(filename)
- }).collect::<Vec<Path>>().move_iter()
- }).collect()
- }
-}
use core::Source;
use sources::PathSource;
use ops;
-use util::{process, CargoResult, ProcessError};
+use util::{CargoResult, ProcessError};
pub fn run_tests(manifest_path: &Path,
options: &mut ops::CompileOptions,
try!(source.update());
let package = try!(source.get_root_package());
- let compiled_libs = try!(ops::compile(manifest_path, options));
-
- let mut exes: Vec<Path> = package.get_targets().iter().filter_map(|target| {
- if !target.get_profile().is_test() { return None }
- let root = package.get_root().join("target");
- let root = match target.get_profile().get_dest() {
- Some(dest) => root.join(dest),
- None => root,
- };
- Some(root.join(target.file_stem()))
- }).collect();
- exes.sort();
+ let mut compile = try!(ops::compile(manifest_path, options));
+ compile.tests.sort();
let cwd = os::getcwd();
- for exe in exes.iter() {
+ for exe in compile.tests.iter() {
let to_display = match exe.path_relative_from(&cwd) {
Some(path) => path,
None => exe.clone(),
};
try!(options.shell.status("Running", to_display.display()));
- match process(exe).args(args).exec() {
+ match compile.process(exe).args(args).exec() {
Ok(()) => {}
Err(e) => return Ok(Some(e))
}
for (lib, name) in libs {
try!(options.shell.status("Doc-tests", name));
- let mut p = process("rustdoc").arg("--test").arg(lib)
- .arg("--crate-name").arg(name)
- .arg("-L").arg("target/test")
- .arg("-L").arg("target/test/deps")
- .cwd(package.get_root());
+ let mut p = compile.process("rustdoc")
+ .arg("--test").arg(lib)
+ .arg("--crate-name").arg(name)
+ .arg("-L").arg("target/test")
+ .arg("-L").arg("target/test/deps")
+ .cwd(package.get_root());
// FIXME(rust-lang/rust#16272): this should just always be passed.
if args.len() > 0 {
p = p.arg("--test-args").arg(args.connect(" "));
}
- for (pkg, libs) in compiled_libs.iter() {
+ for (pkg, libs) in compile.libraries.iter() {
for lib in libs.iter() {
let mut arg = pkg.get_name().as_bytes().to_vec();
arg.push(b'=');
pub use self::cargo_clean::clean;
pub use self::cargo_compile::{compile, CompileOptions};
pub use self::cargo_read_manifest::{read_manifest,read_package,read_packages};
-pub use self::cargo_rustc::compile_targets;
+pub use self::cargo_rustc::{compile_targets, Compilation};
pub use self::cargo_run::run;
pub use self::cargo_new::{new, NewOptions};
pub use self::cargo_doc::{doc, DocOptions};
.with_stderr("`src/main.rs` must be present for \
`cargo run`\n"));
})
+
+test!(run_dylib_dep {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.bar]
+ path = "bar"
+ "#)
+ .file("src/main.rs", r#"
+ extern crate bar;
+ fn main() { bar::bar(); }
+ "#)
+ .file("bar/Cargo.toml", r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+
+ [[lib]]
+ name = "bar"
+ crate-type = ["dylib"]
+ "#)
+ .file("bar/src/lib.rs", "pub fn bar() {}");
+
+ assert_that(p.cargo_process("cargo-run").arg("hello").arg("world"),
+ execs().with_status(0));
+})
[[lib]]
name = "foo"
crate_type = ["dylib"]
+
+ [dependencies.bar]
+ path = "bar"
"#)
.file("src/lib.rs", "
+ extern crate bar;
+
+ pub fn bar() { bar::baz(); }
+
#[test]
- fn foo() {}
+ fn foo() { bar(); }
+ ")
+ .file("tests/test.rs", r#"
+ extern crate foo;
+
+ #[test]
+ fn foo() { foo::bar(); }
+ "#)
+ .file("bar/Cargo.toml", r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+
+ [[lib]]
+ name = "bar"
+ crate_type = ["dylib"]
+ "#)
+ .file("bar/src/lib.rs", "
+ pub fn baz() {}
");
assert_that(p.cargo_process("cargo-test"),
execs().with_status(0)
.with_stdout(format!("\
+{compiling} bar v0.0.1 ({dir})
{compiling} foo v0.0.1 ({dir})
{running} target[..]test[..]foo-[..]
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+{running} target[..]test[..]test-[..]
+
+running 1 test
+test foo ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
{doctest} foo
running 0 tests
assert_that(p.process(cargo_dir().join("cargo-test")),
execs().with_status(0)
.with_stdout(format!("\
+{fresh} bar v0.0.1 ({dir})
{fresh} foo v0.0.1 ({dir})
{running} target[..]test[..]foo-[..]
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+{running} target[..]test[..]test-[..]
+
+running 1 test
+test foo ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
{doctest} foo
running 0 tests
use support::{project, execs};
use hamcrest::assert_that;
+use cargo;
fn setup() {}
assert_that(p.cargo_process("cargo-version"),
execs().with_status(0).with_stdout(format!("{}\n",
- env!("CFG_VERSION")).as_slice()));
+ cargo::version()).as_slice()));
})